#pragma once

/* 假的层 */
#include <metalc/base/mlayer.h>
#include <metalc/meta.h>

/* 计算异或编码 */
typedef struct xorcode{
	size_t xsize;
}xorcode_t;

#define XOR_KEY			(0xAA5555AADEADBEEF)

#define XORCODE_SHOW		(1)
#define xorcode_printf(...)	if (XORCODE_SHOW) INFO(__VA_ARGS__)


#define XORCHK(val, key)	(val ^ key)


OU2INFUN(mmeta, xorcode)

/* TODO:要对齐的话，校验信息一定要放在尾部 */

SAI void _xorcode_pinit(const mlfunc_t * cont, INFUN(xorcode, infun)){
	PARAM_USED(cont);
	infun->mmeta_init();
	xorcode_printf("xorcode pinit\n");
}

SAI void _xorcode_tinit(const mlfunc_t * cont, INFUN(xorcode, infun)){
	PARAM_USED(cont);
	infun->mmeta_tinit();
	xorcode_printf("xorcode tinit\n");
}

/* 如果考虑对齐的问题??增加一套对齐分配接口? */
SAI void   *_xorcode_alloc(mreq_t *req, const mlfunc_t * cont, INFUN(xorcode, infun)){
	
	/* 计算占用大小 */
	/* 不能影响对齐 */
	size_t ori_size = req->size;
	req->size += infun->mmeta_ocupysize(sizeof(xorcode_t));
	// 如果有对齐，重新对齐 /* 需要吗? */
	size_t alignment = req->align;
	if (alignment)
	{
		req->size = align_up(req->size, alignment);
	}
	
	// ASSERT(req->size - ori_size >= infun->mmeta_ocupysize(sizeof(xorcode_t)));
	void *mem = cont->lalloc(req);
	/* 获取大小 */
	req->ptr = mem;
	size_t sz = cont->lsizeof(req);
	// size_t sz = req->size;
	
	fvoid *ret = NULL_PTR;
	if (mem){
		/* 获得写入校验值的区域 */
		xorcode_t *cptr = (xorcode_t *)infun->mmeta_by_ptr(mem, sz, sizeof(xorcode_t), &ret);
		// if ((void *)ret != mem){
		//	 /* !!:影响对齐 */
		xorcode_printf("[m%lx]%p, real size %lx, chkdata write to %p, ori req_size %lx\n", sz, mem, req->size, cptr, ori_size);
		ASSERT((paddr_t)cptr - (paddr_t)mem >= ori_size);
		// }
		/* 写入 */
		// cptr->xptr = (void *)XORCHK((word_t)ret, XOR_KEY);
		cptr->xsize = XORCHK(sz, XOR_KEY);
		// ASSERT(XORCHK((word_t)cptr->xptr, XOR_KEY) == ret);
		// ASSERT(XORCHK((word_t)cptr->xsize, XOR_KEY) == sz);
	}

	req->ptr = mem;
	req->size = sz - infun->mmeta_ocupysize(sizeof(xorcode_t));
	/* 返回指针 */
	return ret;
}

SAI bool_t _xorcode_free(mreq_t *req, const mlfunc_t * cont, INFUN(xorcode, infun)){
	void *mem;
	void *uptr = req->ptr;
	size_t sz = cont->lsizeof(req);
	// size_t sz = req->size - infun->mmeta_ocupysize(sizeof(xorcode_t));
	xorcode_t *cptr = (xorcode_t *)infun->mmeta_by_fptr((fvoid *)uptr, sz, &mem);
	if (mem){
		/* 校验 */
		// void *ptr = (void *)XORCHK((word_t)cptr->xptr, XOR_KEY);
		size_t size = XORCHK(cptr->xsize, XOR_KEY);
		xorcode_printf("[f%lx]%p, mem %p, xor ptr %p, xor size %lx\n", sz, req->ptr, mem, cptr, size);	
		if ((size != sz)) {
			fatal ("[xorcode] chk failed , mem %p may corrupted, real size 0x%lx, xsize 0x%lx\n", req->ptr, req->size, size);
		}
		/* 防止重复释放 */
		cptr->xsize = XOR_KEY;
		/* 继续释放 */
		req->ptr = mem;
	}

	return cont->lfree(req);
}

SAI size_t _xorcode_sizeof(mreq_t *req, const mlfunc_t * cont, INFUN(xorcode, infun)){
	/* 可用大小要减 */
	return cont->lsizeof(req) - infun->mmeta_ocupysize(sizeof(xorcode_t));
}

/*
	定义xorcode层的mmeta获得方法, xorcode的计算方法
*/
#define DEF_XORCODE_MLAYER(name, mmeta_name)\
DEF_MLAYER_BASIC(name, -1, 0)\
SAI void name##_pinit(const mlfunc_t * cont){ return _xorcode_pinit(cont, OUFUN_OF(mmeta_name)); }\
SAI void name##_tinit(const mlfunc_t * cont){return _xorcode_tinit(cont, OUFUN_OF(mmeta_name)); }\
SAI void *name##_alloc(mreq_t *req, const mlfunc_t * cont){\
	return _xorcode_alloc(req, cont, OUFUN_OF(mmeta_name));\
}\
SAI bool_t name##_free(mreq_t *req, const mlfunc_t * cont){\
	return _xorcode_free(req, cont, OUFUN_OF(mmeta_name));\
}\
SAI size_t name##_sizeof(mreq_t *req, const mlfunc_t * cont){\
	return _xorcode_sizeof(req, cont, OUFUN_OF(mmeta_name));\
}

DEF_MMETA_TL_PURE(xor_tail, xorcode_t, sizeof(xorcode_t))

DEF_XORCODE_MLAYER(xor_tail, xor_tail)
